package org.apache.commons.pool2.impl;

import org.apache.commons.pool2.PooledObjectFactory;

import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import java.lang.reflect.TypeVariable;

/**
 * 类的描述
 *
 * @author ztkool
 * @version v
 */
class PoolImplUtils {
    PoolImplUtils() {
    }

    static Class<?> getFactoryType(Class<? extends PooledObjectFactory> factoryClass) {
        Class<PooledObjectFactory> type = PooledObjectFactory.class;
        Object genericType = getGenericType(type, factoryClass);
        if (genericType instanceof Integer) {
            ParameterizedType pi = getParameterizedType(type, factoryClass);
            if (pi != null) {
                Type[] bounds = ((TypeVariable) pi.getActualTypeArguments()[(Integer) genericType]).getBounds();
                if (bounds != null && bounds.length > 0) {
                    Type bound0 = bounds[0];
                    if (bound0 instanceof Class) {
                        return (Class) bound0;
                    }
                }
            }

            return Object.class;
        } else {
            return (Class) genericType;
        }
    }

    private static <T> Object getGenericType(Class<T> type, Class<? extends T> clazz) {
        if (type != null && clazz != null) {
            ParameterizedType pi = getParameterizedType(type, clazz);
            if (pi != null) {
                return getTypeParameter(clazz, pi.getActualTypeArguments()[0]);
            } else {
                Class<? extends T> superClass = (Class<? extends T>) clazz.getSuperclass();
                Object result = getGenericType(type, superClass);
                if (result instanceof Class) {
                    return result;
                } else if (result instanceof Integer) {
                    ParameterizedType superClassType = (ParameterizedType) clazz.getGenericSuperclass();
                    return getTypeParameter(clazz, superClassType.getActualTypeArguments()[(Integer) result]);
                } else {
                    return null;
                }
            }
        } else {
            return null;
        }
    }

    private static <T> ParameterizedType getParameterizedType(Class<T> type, Class<? extends T> clazz) {
        Type[] var2 = clazz.getGenericInterfaces();
        int var3 = var2.length;

        for (int var4 = 0; var4 < var3; ++var4) {
            Type iface = var2[var4];
            if (iface instanceof ParameterizedType) {
                ParameterizedType pi = (ParameterizedType) iface;
                if (pi.getRawType() instanceof Class && type.isAssignableFrom((Class) pi.getRawType())) {
                    return pi;
                }
            }
        }

        return null;
    }

    private static Object getTypeParameter(Class<?> clazz, Type argType) {
        if (argType instanceof Class) {
            return argType;
        } else {
            TypeVariable<?>[] tvs = clazz.getTypeParameters();

            for (int i = 0; i < tvs.length; ++i) {
                if (tvs[i].equals(argType)) {
                    return i;
                }
            }

            return null;
        }
    }
}
